package cn.szsys.integration.util;

import lombok.extern.slf4j.Slf4j;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Ryan
 * @since 2025-05-08
 **/
public class EncryptUtil {

    @Slf4j
    public static class ECB {
        private static final String ALG_AES = "AES/ECB/PKCS5Padding";
        private static final String NAME_AES = "AES";
        private static final Map<String, Map<Integer, Cipher>> CIPHERS = new HashMap<>();

        private static Cipher getCipher(String key, int mode) throws InvalidKeyException, NoSuchAlgorithmException,
                NoSuchPaddingException {
            KeyGenerator keyGen = KeyGenerator.getInstance(NAME_AES);
            SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
            sr.setSeed(key.getBytes(StandardCharsets.UTF_8));
            keyGen.init(128, sr);
            SecretKey secKey = keyGen.generateKey();
            byte[] raw = secKey.getEncoded();

            Map<Integer, Cipher> modeCipher;
            Cipher cipher;
            if ((modeCipher = CIPHERS.get(key)) == null) {
                cipher = Cipher.getInstance(ALG_AES);
                cipher.init(mode, new SecretKeySpec(raw, NAME_AES));
                modeCipher = new HashMap<>(2);
                modeCipher.put(mode, cipher);
                CIPHERS.put(key, modeCipher);
            } else {
                if ((cipher = modeCipher.get(mode)) == null) {
                    cipher = Cipher.getInstance(ALG_AES);
                    cipher.init(mode, new SecretKeySpec(raw, NAME_AES));
                    modeCipher.put(mode, cipher);
                }
            }
            return cipher;
        }

        /**
         * 解密
         *
         * @param source source
         * @param key    key
         * @return {@link String}
         * @author Ryan
         */
        public static String decode(String source, String key) {
            String decryptStr = null;
            try {
                byte[] decryptByte = getCipher(key, Cipher.DECRYPT_MODE).doFinal(Base64Util.decode(source));
                decryptStr = new String(decryptByte, StandardCharsets.UTF_8);
            } catch (Exception e) {
                log.error("解密失败", e);
            }
            return decryptStr;
        }

        /**
         * 解密
         *
         * @param source accessKey+时间戳
         * @param key    accessKeySecret
         * @return {@link String}
         * @author Ryan
         */
        public static String encode(String source, String key) {
            String encryptStr = null;
            try {
                byte[] encryptByte = getCipher(key, Cipher.ENCRYPT_MODE).doFinal(source.getBytes(StandardCharsets.UTF_8));
                encryptStr = Base64Util.encode(encryptByte);
                return encryptStr;
            } catch (Exception e) {
                log.error("加密失败", e);
            }
            return encryptStr;
        }
    }

    public static class CBC {
        /**
         * 加密算法
         */
        public static final String ENCRYPT_ALGORITHM = "AES";

        /**
         * 加密算法/加密模式/填充类型
         * 本例采用AES加密，ECB加密模式，PKCS5Padding填充
         */
        private static final String CIPHER_MODE = "AES/CBC/PKCS5Padding";


        /**
         * AES 密钥长度（128, 192, 256 位）
         */
        private static final int AES_KEY_SIZE = 128;

        /**
         * 初始化向量大小，AES 块大小为 16 字节
         */
        private static final int IV_SIZE = 16;

        public static void main(String[] args) throws Exception {
            String plaintext = "This is a secret message";

            // 生成 AES 密钥
            SecretKey secretKey = generateAESKey();

            // 生成初始化向量（IV）
            IvParameterSpec iv = generateIv();

            // 加密
            String cipherText = encrypt(plaintext, secretKey, iv);
            System.out.println("加密后的文本: " + cipherText);

            // 解密
            String decryptedText = decrypt(cipherText, secretKey, iv);
            System.out.println("解密后的文本: " + decryptedText);
        }

        /**
         * 生成 AES 密钥
         *
         * @return {@link SecretKey}
         * @author rhf
         */
        public static SecretKey generateAESKey() throws Exception {
            KeyGenerator keyGenerator = KeyGenerator.getInstance(ENCRYPT_ALGORITHM);
            keyGenerator.init(AES_KEY_SIZE);
            return keyGenerator.generateKey();
        }

        /**
         * 生成初始化向量（IV）
         *
         * @return {@link IvParameterSpec}
         * @author rhf
         */
        public static IvParameterSpec generateIv() {
            byte[] iv = new byte[IV_SIZE];
            new SecureRandom().nextBytes(iv);
            return new IvParameterSpec(iv);
        }

        /**
         * 加密方法
         *
         * @param plaintext plaintext
         * @param key       key
         * @param iv        iv
         * @return {@link String}
         * @author rhf
         */
        public static String encrypt(String plaintext, SecretKey key, IvParameterSpec iv) throws Exception {
            Cipher cipher = Cipher.getInstance(CIPHER_MODE);
            cipher.init(Cipher.ENCRYPT_MODE, key, iv);
            byte[] cipherText = cipher.doFinal(plaintext.getBytes());
            return Base64.getEncoder().encodeToString(cipherText);
        }

        /**
         * @param plaintext plaintext
         * @param key       key
         * @param value     使用CommonUtil的getValue
         * @return {@link String}
         * @author rhf
         */
        public static String encrypt(String plaintext, SecretKey key, String value) throws Exception {
            Cipher cipher = Cipher.getInstance(CIPHER_MODE);
            IvParameterSpec ivParameterSpec = new IvParameterSpec(value.getBytes());
            cipher.init(Cipher.ENCRYPT_MODE, key, ivParameterSpec);
            byte[] cipherText = cipher.doFinal(plaintext.getBytes());
            return Base64.getEncoder().encodeToString(cipherText);
        }

        /**
         * 解密方法
         *
         * @param cipherText cipherText
         * @param key        key
         * @param iv         iv
         * @return {@link String}
         * @author rhf
         */
        public static String decrypt(String cipherText, SecretKey key, IvParameterSpec iv) throws Exception {
            Cipher cipher = Cipher.getInstance(CIPHER_MODE);
            cipher.init(Cipher.DECRYPT_MODE, key, iv);
            byte[] plainText = cipher.doFinal(Base64.getDecoder().decode(cipherText));
            return new String(plainText);
        }
    }

}

